package com.xiangxiao.rpan.storage.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.xiangxiao.rpan.storage.dao.ReadmeConfigMapper;
import com.xiangxiao.rpan.storage.entity.FileItemResult;
import com.xiangxiao.rpan.storage.entity.ReadmeConfig;
import com.xiangxiao.rpan.storage.enums.ReadmeDisplayModeEnum;
import com.xiangxiao.rpan.storage.factory.StorageSourceContext;
import com.xiangxiao.rpan.storage.service.AbstractBaseFileService;
import com.xiangxiao.rpan.storage.service.ReadmeConfigService;
import com.xiangxiao.rpan.storage.utils.PatternMatcherUtils;
import com.xiangxiao.rpan.storage.utils.StringUtil;
import com.xiangxiao.rpan.utils.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * @auther xiangxiao
 * @email 573768011@qq.com
 * @data 2023/11/16 20:48
 */
@Slf4j
@Service
public class ReadmeConfigServiceImpl implements ReadmeConfigService {
  @Resource
  private SqlSessionFactory sqlSessionFactory;

  @Resource
  private ReadmeConfigMapper readmeConfigMapper;

  @Resource
  private StorageSourceContext storageSourceContext;

  @Override
  public List<ReadmeConfig> findByStorageId(Integer storageId) {
    return readmeConfigMapper.findByStorageId(storageId);
  }

  public int deleteByStorageId(Integer storageId) {
    int deleteSize = readmeConfigMapper.deleteByStorageId(storageId);
    log.info("删除存储源 ID 为 {} 的目录文档配置 {} 条", storageId, deleteSize);
    return deleteSize;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchSave(Integer storageId, List<ReadmeConfig> readmeConfigList) {
    deleteByStorageId(storageId);
    log.info("更新存储源 ID 为 {} 的目录文档配置 {} 条", storageId, readmeConfigList.size());

    // 开启批量处理模式BATCH, 关闭自动提交事务的机制,改成全部数据一次性提交,更新完毕后再关闭sqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
    long startTime = System.currentTimeMillis();
    readmeConfigList.forEach(readmeConfig -> {
      readmeConfig.setStorageId(storageId);
      readmeConfigMapper.insertSingle(readmeConfig);

      if (log.isDebugEnabled()) {
        log.debug("新增目录文档, 存储源 ID: {}, 表达式: {}, 描述: {}, 显示模式: {}",
            readmeConfig.getStorageId(), readmeConfig.getExpression(),
            readmeConfig.getDescription(), readmeConfig.getDisplayMode().getValue());
      }
    });
    // 一次性提交事务
    sqlSession.commit();
    sqlSession.close();
    long endTime = System.currentTimeMillis();
    log.info("总耗时:" + (endTime - startTime)  + "豪秒");
  }

  @Override
  public ReadmeConfig getByStorageAndPath(Integer storageId, String path, Boolean compatibilityReadme) {
    ReadmeConfig readmeByPath = new ReadmeConfig();
    readmeByPath.setStorageId(storageId);
    readmeByPath.setDisplayMode(ReadmeDisplayModeEnum.BOTTOM);
    if (BooleanUtil.isTrue(compatibilityReadme)) {
      try {
        log.info("存储源 {} 兼容获取目录 {} 下的 readme.md", storageId, path);
        AbstractBaseFileService<com.xiangxiao.rpan.storage.params.IStorageParam> abstractBaseFileService = storageSourceContext.getByStorageId(storageId);
        String pathAndName = StringUtil.concat(path, "readme.md");
        FileItemResult fileItem = abstractBaseFileService.getFileItem(pathAndName);
        if (fileItem != null) {
          String url = fileItem.getUrl();
          String readmeText = HttpUtil.getTextContent(url);
          readmeByPath.setReadmeText(readmeText);
        }
      } catch (Exception e) {
        log.error("存储源 {} 兼容获取目录 {} 下的 readme.md 文件失败", storageId, path, e);
      }
    } else {
      // 获取指定目录 readme 文件
      ReadmeConfig dbReadmeConfig = this.findReadmeByPath(storageId, path);
      if (dbReadmeConfig != null) {
        readmeByPath = dbReadmeConfig;
      }
      log.info("存储源 {} 规则模式获取目录 {} 下文档信息", storageId, path);
    }

    return readmeByPath;
  }

  @Override
  public ReadmeConfig findReadmeByPath(Integer storageId, String path) {
    List<ReadmeConfig> readmeConfigList = this.findByStorageId(storageId);
    return this.getReadmeByTestPattern(storageId, readmeConfigList, path);
  }

  private ReadmeConfig getReadmeByTestPattern(Integer storageId, List<ReadmeConfig> patternList, String test) {
    // 如果目录文档规则为空, 则可直接返回空.
    if (CollUtil.isEmpty(patternList)) {
      if (log.isDebugEnabled()) {
        log.debug("目录文档规则列表为空, 存储源 ID: {}, 测试字符串: {}", storageId, test);
      }
      return null;
    }

    for (ReadmeConfig filterConfig : patternList) {
      String expression = filterConfig.getExpression();

      if (StrUtil.isEmpty(expression)) {
        if (log.isDebugEnabled()) {
          log.debug("存储源 {} 目录文档规则表达式为空: {}, 测试字符串: {}, 表达式为空，跳过该规则比对", storageId, expression, test);
        }
        continue;
      }

      try {
        boolean match = PatternMatcherUtils.testCompatibilityGlobPattern(expression, test);

        if (log.isDebugEnabled()) {
          log.debug("存储源 {} 目录文档规则表达式: {}, 测试字符串: {}, 匹配结果: {}", storageId, expression, test, match);
        }

        if (match) {
          return filterConfig;
        }
      } catch (Exception e) {
        log.error("存储源 {} 目录文档规则表达式: {}, 测试字符串: {}, 匹配异常，跳过该规则.", storageId, expression, test, e);
      }
    }

    return null;
  }
}
